"""
sequence of events
1. Production planning: consumption and capital firms compute their desired output level.

"""
import random
import uuid
import numpy as np
from typing import List
from utils import ParaPro, LOGG
from contract import DepositContract, LoanContract, JobContract, ConsumptionGoodsContract
import pandas as pd

p = ParaPro()
INI_YEAR = 1992
cfg = {'gov': True}


def prt(*args):
    if p.ctrl.print:
        print(*args)


def apt(*args):
    if p.ctrl.apt:
        print(*args)


class HouseHolds:
    def __init__(self, ini_id, ini_deposit):
        # 由家庭向公司出售劳动力以换取工资，
        # 以银行存款的形式消费和储蓄。
        # 家庭按其财富比例拥有公司和银行，并
        # 从公司和银行的利润中获得一部分作为股息。
        # 失业工人从政府获得救济金。
        # 最后，家庭为其总收入纳税。

        self.employed_history = []  # 后续在劳动力市场补充
        self.household_id = ini_id  # 如何初始化id，不能重复
        self.wages = p.h.households_wage  # 初始化工资
        self.deposits = ini_deposit  # 初始化存款 # 存量
        self.deposits_bank_id = ''
        self.consume_firm_id = ''
        self.hold_stock_of_firm = {}  # 占位
        self.hold_stock_of_bank = {}  # 展位
        self.wealth = ini_deposit

    def update_wages_contract(self, rate_of_unemployment):
        # 居民和企业(雇主)重新议价
        # 如果居民连续两个季度都没有找到工作，那么其降低自己的工资要求
        # 如果居民发现物价上涨超过一定的阈值，那么就要求涨工资以满足自身的购买力
        rd_value = abs(np.random.normal(p.a.normal_d_mean, p.a.normal_d_dev))  # 得到一个随机数
        if all(not t_f for t_f in self.employed_history[-3:]):  # 连续两期失业
            self.wages = self.wages * (1 - rd_value)
        elif rate_of_unemployment < p.ratio.unemployment_rate_target:  # 总体失业率低于目标值
            self.wages = self.wages * (1 + rd_value)
        return self.wages

    def consume(self, price):
        # 以银行存款的形式消费和储蓄
        a1 = self.wages * p.h.households_consumption_para_1 / price
        a2 = self.wealth * p.h.households_consumption_para_2 / price
        return int(a1 + a2)


class Firms:
    def __init__(self, ini_id, firm_type, ini_inventory, ini_unit_cost, ini_deposits, ini_loans, ini_capital,
                 ini_amortization):
        self.year = INI_YEAR
        self.firm_id = ini_id
        self.firm_type = firm_type  # ['Capital Goods', 'Consumer Goods']
        self.ask_price = 0  # 占位
        self.supplier_k_firm_id = ''  # 占位
        self.worker_list = []
        self.wage_list = []
        # 流量flow
        self.sales_list = []

        self.amortization = ini_amortization
        self.unit_cost_last_period = ini_unit_cost  # 会计准则，计算存货估值的变动
        self.unit_cost_this_period = ini_unit_cost  # 会计准则，计算存货估值的变动

        self.rate_of_return_last_period = 0
        self.rate_of_return_this_period = 0
        self.paras = {
        }
        # 价格
        if self.firm_type == 'Capital Goods':
            self.markup = p.m.mark_up_of_capital  # 论文设定
            self.sales_last_period = p.y.output_of_capital / p.n.number_of_k_firms
            # 销售，流量，上一期(初始化赋值) 5375这个数字来源于交易流量矩阵
        else:
            self.markup = p.m.mark_up_of_consumption  # 论文设定
            self.sales_last_period = p.y.output_of_consumption / p.n.number_of_c_firms
        # 存量stock
        self.inventory = ini_inventory
        self.inventory_start = ini_inventory  # 初始化库存,存量，期初存量
        self.inventory_end = 0  # 初始化期末库存，存量，期末库存
        # 资本
        self.capital = ini_capital
        self.capital_start = ini_capital  # 资本存量
        self.capital_end = 0  # 占位，用于计算投资品数量
        # 存款
        self.deposits = ini_deposits
        self.deposits_bank_id = ''
        # 贷款
        self.loans = ini_loans
        self.loans_bank_id = ''
        # batch
        self.batch_of_capital = self.ini_batch_of_capital()
        self.batch_of_loan_contracts = [LoanContract({})]
        #
        self.y = 0  # 占位用，不需要初始化赋值
        self.payment_of_wages_list = []  # 用于存储公司发工资的容器，运行完要清空
        self.payment_of_loans_list = self.ini_payment_of_loans_list()  # 公司在历史不同时期的贷款
        self.deposits_contract = DepositContract({})  # 后续在CreditMarket里面根据贷款合同赋值

    def ini_payment_of_loans_list(self):
        total_loans = self.loans
        latest_loans = p.para.factor_of_batch_loan * total_loans
        d = p.para.duration_or_loan
        ss = p.ss.steady_state_rate
        return [latest_loans * (d - i) / (d * (1 + ss) ** i) for i in range(int(d))]

    def update_new_period(self):
        """
        重置新状态，存货和成本
        :return:
        """
        self.inventory_start = self.inventory
        self.unit_cost_last_period = self.unit_cost_this_period

    def ini_batch_of_capital(self):
        """
        初始化资本品
        :return:
        """
        if self.firm_type == 'Consumer Goods':
            return {
                0: {'ini_capital': 20,
                    'price': 1,
                    'left_capital': 19,
                    'age': 1,
                    'left_age': 19}}  # 初始资本20,用了1年，还剩下残值19，剩余折旧年限19
        else:
            return {}

    def expected_sales(self):
        if self.year == INI_YEAR:
            return self.sales_last_period * (1 + p.ss.steady_state_rate)
        else:
            # 采用的预期公式
            expected_sales = self.expected_sales_last_period + p.a.adaptive_lambda * (
                    self.sales_last_period - self.expected_sales_last_period)
        return expected_sales

    def output_decision(self):
        # 公司的产出决策，首先公司会对本期形成预期销售额，然后根据持有的存货意愿和上期末存货确定本期生产数量
        # y_{xt}^D = s_{xt}^e(1 + \nu) - inv_{xt-1}
        expected_sales = self.expected_sales()
        self.y = expected_sales * (1 + p.ratio.ratio_of_inventory_to_output) - self.inventory_start
        apt('output decision', self.firm_type, self.y)

    def needed_works(self):
        # 通过产量和生产率计算出需要的人数
        self.output_decision()
        if self.firm_type == 'Consumer Goods':
            capacity_utilization = min(1, self.y / (self.capital_start * p.para.productivity_of_c_firm))
            self.paras['workers_needed_this_period'] = int(
                self.capital_start * capacity_utilization / p.ratio.labor_capital_ratio)
        else:
            self.paras['workers_needed_this_period'] = int(self.y / p.para.productivity_of_k_firm)

    @property
    def cal_payment_of_wages(self):
        if len(self.payment_of_wages_list) == 0:
            return np.sum(self.wage_list)
        else:
            self.paras['average_wage_last_period'] = np.average(self.payment_of_wages_list)
            return np.sum(self.payment_of_wages_list)

    @property
    def cal_interests_payment_of_loans(self):
        return sum([contract.amount * contract.interest_rate for contract in self.batch_of_loan_contracts])

    @property
    def cal_principle_payment_of_loans(self):
        return sum([contract.amount / contract.left_year for contract in self.batch_of_loan_contracts])

    def unit_cost(self):
        """
        单位成本等于工资成本加上资本摊销除以产量
        :return:
        """
        self.needed_works()
        payment_of_wages = self.cal_payment_of_wages
        if self.firm_type == 'Consumer Goods':
            unit_cost = (self.capital_amortization() + payment_of_wages) / self.y
        else:
            unit_cost = payment_of_wages / self.y
        return unit_cost

    def pricing(self, year):
        """
        The markup is endogenously revised from period to period following a simple adaptive rule. When firms in the
        previous period end up having more inventories than desired, the markup is lowered in order to increase the
        attractiveness of their output
        加成是内生通过上期数据自适应确定的，当公司上期库存销售比高于预期，那么其利润加成就下调，当公司上期库存销售比低于预期，那么其利润加成
        上升
        注意：定价的时候还没有形成真实工资，所以采用了预期平均工资
        本函数一轮调用一次
        """
        if year == INI_YEAR:
            mark_up = self.markup
            expected_average_wage = np.average(self.wage_list) * (1 + p.ss.steady_state_rate)
            self.paras['expected_average_wage_last_period'] = expected_average_wage
        else:
            inv_ratio_last_period = self.inventory_start / self.sales_last_period  # 利润销售比
            rd_value = np.random.normal(p.a.normal_d_mean, p.a.normal_d_dev)  # 得到一个随机数
            expected_average_wage = self.paras['expected_average_wage_last_period'] + p.a.adaptive_lambda * (
                    self.paras['average_wage_last_period'] - self.paras['expected_average_wage_last_period'])
            if inv_ratio_last_period <= p.ratio.ratio_of_inventory_to_output:
                mark_up = self.markup * (1 + rd_value)
            else:
                mark_up = self.markup * (1 - rd_value)
        ask_price = (1 + mark_up) * expected_average_wage * self.paras['workers_needed_this_period'] / self.y
        self.paras['ask_price'] = ask_price
        self.ask_price = ask_price
        return self.ask_price

    @property
    def sales_revenue(self):
        """
        获取销售收入
        :return:
        """
        return np.sum(self.sales_list)

    def capital_amortization(self):
        """
        资本摊销,调用意味着摊销了，改变了资本状态
        :return:
        """
        if self.year == INI_YEAR:
            return self.amortization
        else:
            ini_amortization = 0
            for id_capital, batch_capital in self.batch_of_capital.items():
                temp_amort = batch_capital['ini_capital'] * batch_capital['price'] / p.para.duration_or_capital
                ini_amortization += temp_amort
            return ini_amortization

    def nominal_variation_of_inventories(self):
        """
        根据标准的会计准则，计算存货估值的变动
        :return:
        """
        if 'nvi' not in self.paras:
            self.unit_cost_this_period = self.unit_cost()
            unit_cost = self.unit_cost_this_period
            end_inv = self.inventory
            start_inv = self.inventory_start
            start_cost = self.unit_cost_last_period
            variation_of_inv = end_inv * unit_cost - start_inv * start_cost
            self.paras['nvi'] = variation_of_inv
        else:
            variation_of_inv = self.paras['nvi']
        return variation_of_inv

    def profits(self, expected=True):
        """
        C公司：销售收入 + 存款利息 + 存货估值变动 - 工资支出 - 贷款利息支出 - 资本摊销
        K公司：销售收入 + 存款利息 + 存货估值变动 - 工资支出 - 贷款利息支出
        :return:
        """
        expected_sales = self.expected_sales()
        self.paras['expected_sales_money'] = expected_sales * self.ask_price
        self.paras['sales_money'] = self.sales_revenue
        dep_interests = self.deposits_contract.interest_per_year
        self.paras['deposits_interests'] = dep_interests
        self.paras['nominal_variation_of_inventories'] = self.nominal_variation_of_inventories()
        if expected:
            inflow_li = [self.paras[v] for v in
                         ['expected_sales_money', 'deposits_interests', 'nominal_variation_of_inventories']]
        else:
            inflow_li = [self.paras[v] for v in
                         ['sales_money', 'deposits_interests', 'nominal_variation_of_inventories']]

        self.paras['loan_interests'] = self.cal_interests_payment_of_loans
        self.paras['expected_payment_of_wages'] = self.cal_payment_of_wages
        outflow_li = [self.paras[v] for v in ['loan_interests', 'expected_payment_of_wages']]
        profits = sum(inflow_li) - sum(outflow_li)
        if self.firm_type == 'Consumer Goods':
            profits -= self.capital_amortization()  # 消费品公司需要资本摊销
        self.paras['profits'] = profits
        return profits

    @property
    def dividends(self):
        profits = self.paras['profits']
        d = max(0, (1 - p.ratio.ratio_of_dividends_to_profits_left) * profits * (1 - p.ratio.tax_rate))
        self.paras['dividends'] = d
        return d

    def ocf(self):
        # 自由现金流
        after_tax_profits = self.profits(expected=True) * (1 - p.ratio.tax_rate)
        ocf = after_tax_profits - self.nominal_variation_of_inventories() - self.cal_principle_payment_of_loans
        if self.firm_type == 'Consumer Goods':
            ocf += self.capital_amortization()  # 消费品公司需要在现金流中加回资本摊销
        return ocf

    @property
    def investment(self):
        """
        公司资产的目标跟收益率只差成正比（如果本期收益率大于上期收益率，那么就要求资产有一个增速），具体的投资额为期末和期初投资额之差加上摊销的
        部分。
        :return:
        """
        assert self.firm_type == 'Consumer Goods'

        if self.year > INI_YEAR:
            self.rate_of_return_this_period = self.ocf() / self.capital_end
            capital_growth = p.a.c_firm_investment_elasticity * (
                    self.rate_of_return_this_period - self.rate_of_return_last_period)
        else:
            capital_growth = p.ss.steady_state_rate
        self.capital_end = self.capital_start * (1 + capital_growth)
        return int(max(0, self.capital_end - self.capital_start + self.capital_amortization()))

    @property
    def finance(self):
        # deposits_needed = p.ratio.ratio_of_deposits_to_wage * self.cal_payment_of_wages
        self.profits(expected=True)
        if self.firm_type == 'Consumer Goods':
            # finance = self.paras['nominal_investment'] + self.dividends + deposits_needed - self.ocf()
            finance = self.paras['nominal_investment'] + self.dividends - self.ocf()
            return finance
        else:
            # return self.dividends + deposits_needed - self.ocf()
            return self.dividends - self.ocf()

    def production(self):
        """
        生产过程，工人把自己劳动力和利用资本（K，如有）转化为商品，公司存货增加y，但此时还没有销售出去
        :return:
        """
        self.inventory += self.y


class Banks:
    def __init__(self, ini_id, ini_reserves, ini_loans, ini_bonds, ini_deposits, ini_cash_advance):
        self.bank_id = ini_id
        self.capital_ratio_targets = p.b.capital_ratio_target  # 流动比率 NW / Loan
        self.liquidity_ratio_target = p.b.mandatory_liquidity_ratio
        self.bonds_interests_payment = 0  # 占位，后续在events 12 支付债券利息中赋值
        self.loan_interest_rate = p.ir.interest_rate_of_loans  # 贷款利率
        self.deposit_interest_rate = p.ir.interest_rate_of_deposits  # 存款利率
        self.cash_advance_interest_rate = 1  # cash advance rate 银行向央行短期借款利率

        # 银行资产
        self.reserves = ini_reserves  # 保证金，银行资产
        self.loans = ini_loans  # 贷款，银行资产
        self.bonds = ini_bonds  # 银行持有的政府债券
        # 银行负债
        self.deposits = ini_deposits  # 存款，银行负债
        self.cash_advance = ini_cash_advance  # 银行向中央银行的预借款
        # 银行净资产
        self.net_wealth = self.reserves + self.loans + self.bonds - self.deposits - self.cash_advance  # 净资产
        # 比率
        self.non_performing_loans = 0  # 违约贷款

    def set_loan_interest_rate(self):
        """
        当银行 Capital_ratio(net_wealth / loan)低于目标值,意味着贷款过多，则需要降低贷款，这时候贷款利率随机增加
        当其高于目标值，意味着可放贷的空间比较大，这时候贷款随机利率降低。
        :return:
        """
        rd_value = abs(np.random.normal(p.a.normal_d_mean, p.a.normal_d_dev))
        apt(f"银行{self.bank_id}原始利率为{self.loan_interest_rate}")
        if self.calculate_capital_ratio() > self.capital_ratio_targets:
            self.loan_interest_rate = self.loan_interest_rate * (1 + rd_value)
        else:
            self.loan_interest_rate = self.loan_interest_rate * (1 - rd_value)
        apt(f"银行{self.bank_id}重新设置利率为{self.loan_interest_rate}")

    def set_deposit_interest_rate(self):
        """
        银行设定存款利率，如果流动资金比率，表示为存款准备金/存款，高于目标值，则需要降低存款利率
        当liquidity ratio低于目标设定，银行将存款利率随机增加一个值（正态分布）
        :return:
        """
        rd_value = np.random.normal(p.a.normal_d_mean, p.a.normal_d_dev)
        apt(f"银行{self.bank_id}原始存款利率为{self.deposit_interest_rate}")
        if self.calculate_liquidity_ratio() >= self.liquidity_ratio_target:
            self.deposit_interest_rate = self.deposit_interest_rate * (1 + rd_value)
        else:
            self.deposit_interest_rate = self.deposit_interest_rate * (1 - rd_value)
        apt(f"银行{self.bank_id}重新设置存款利率为{self.deposit_interest_rate}")

    def cal_average_loan_interest_rate(self):
        """
        计算贷款加权平均利率
        :return:
        """

    def calculate_liquidity_ratio(self):
        return self.reserves / self.deposits

    def calculate_capital_ratio(self):
        # (net_wealth / loan)
        return self.net_wealth / self.loans

    @property
    def profits(self):
        loan_interests = self.loans * self.loan_interest_rate
        deposits_interests = self.deposits * self.deposit_interest_rate
        bonds = self.bonds_interests_payment  # self.bonds_interests_payment 需要
        return bonds + loan_interests - deposits_interests

    @property
    def dividends(self):
        return self.profits * (1 - p.ratio.tax_rate)

    def calculate_capital_ratio(self):
        return self.net_wealth / self.loans  # 资本充足率 = 资本 / 加权风险资产

    def available_money_for_buy_bonds(self):
        assets = self.loans + self.bonds + self.reserves
        debt = self.deposits - self.cash_advance
        bank_net_worth = assets - debt
        available_money = min(bank_net_worth, p.ratio.bank_min_reserve_rate * self.reserves)
        return available_money

    def ask_for_cash_advance(self):
        if self.reserves / self.deposits >= p.b.mandatory_liquidity_ratio:
            return 0
        else:
            pctg = p.b.mandatory_liquidity_ratio - self.reserves / self.deposits
            return pctg * self.deposits


class Government:
    def __init__(self):
        self.deposits = 0
        self.bonds_collection = []  # 一批债券集合
        self.bonds = p.g.bonds_government_issue  # 政府负债
        self.worker_list = []  # 劳动力市场初始化会补充
        self.wage_list = []  # 劳动力市场初始化


class CentralBank:
    def __init__(self):
        # 经济中的货币不包括通货，居民财富以银行存款，银行将一定比例的保证金存到央行
        self.reserves = p.b.bank_reserves  # 中央银行负债
        self.cash_advances = 0  # 中央银行资产
        self.bonds_collection = []  # 中央银行持有政府债券
        self.bonds = p.g.bonds_government_issue - p.b.bank_hold_bonds  # 中央银行持有政府债券金额
        self.treasury_deposits = 0  # 财政存款


class ConsumptionGoodsMarket:
    def __init__(self,
                 c_firms: List[Firms],
                 households: List[HouseHolds],
                 households_matching_consumption_book: dict,
                 ):

        self.c_firms: List[Firms] = c_firms
        self.households: List[HouseHolds] = households

        self.c_firms_id = [f.firm_id for f in self.c_firms]
        self.households_consumption_contract_book = households_matching_consumption_book

    def search_household_by_id(self, household_id):
        all_h_id = [s.household_id for s in self.households]
        idx = all_h_id.index(household_id)
        return self.households[idx]

    def search_c_firm_by_id(self, firm_id):
        for c in self.c_firms:
            if c.firm_id == firm_id:
                return c

    def observe_price(self):
        """
        c(消费)公司，每一个都会受到n个k（资本品供应商）的报价
        :return:
        """
        price_collection = {}
        num_c = int(p.a.degree_of_imperfect_information * len(self.c_firms_id))  # 确定报价数量
        all_ask_price = {f.firm_id: f.ask_price for f in self.c_firms}
        for h in self.households:
            filter_c_firms = random.sample(self.c_firms, num_c)
            price_collection[h.household_id] = {f.firm_id: all_ask_price[f.firm_id] for f in filter_c_firms}
        return price_collection, all_ask_price

    def update_c_supplier(self):
        contract_book = self.households_consumption_contract_book
        c_firms_bid_price_for_h, all_c_firm_bid_price = self.observe_price()  # 这个函数一个循环只能调用一次
        for household_id, c_firm_id in contract_book.items():
            contract_ask_price = all_c_firm_bid_price[c_firm_id]
            # 获取竞争者报价清单，要注意竞争者报价在
            other_c_firm_ask_price_collection = c_firms_bid_price_for_h[household_id]
            competitor_firm_id = min(other_c_firm_ask_price_collection, key=other_c_firm_ask_price_collection.get)
            competitor_price = other_c_firm_ask_price_collection[competitor_firm_id]
            # 如果竞争者最低报价小于当前的供应商报价，那么有一定概率切换供应商
            if competitor_price < contract_ask_price:
                if random.random() <= p.a.probability_of_switch:
                    self.households_consumption_contract_book[household_id] = competitor_firm_id

    def format_contract_between_c_firms_and_households(self, year):
        contract_collection = []
        for household_id, c_firm_id in self.households_consumption_contract_book.items():
            h = self.search_household_by_id(household_id)
            c_firm = self.search_c_firm_by_id(c_firm_id)
            contract = {'household_id': h.household_id, 'c_firm_id': c_firm.firm_id, 'price': c_firm.ask_price,
                        'quantity': h.consume(c_firm.pricing(year))}
            contract_collection.append(ConsumptionGoodsContract(contract))
        return contract_collection


class CapitalGoodsMarket:
    def __init__(self,
                 year: int,  # 开始年份
                 c_firms: List[Firms],
                 k_firms: List[Firms],
                 c_firm_match_k_firm: dict):
        self.year = year
        self.c_firms: List[Firms] = c_firms
        self.k_firms: List[Firms] = k_firms

        self.c_firms_id = [s.firm_id for s in self.c_firms]
        self.k_firms_id = [s.firm_id for s in self.k_firms]

        self.c_firm_supplier_contract_book = c_firm_match_k_firm  # c公司初始状态下的k公司供应商

    def search_firm_by_id(self, firm_id) -> Firms:
        for c_firm in self.c_firms:
            if c_firm.firm_id == firm_id:
                return c_firm
        for k_firm in self.k_firms:
            if k_firm.firm_id == firm_id:
                return k_firm

    def c_firms_observe_k_firms_price(self):
        """
        c(消费)公司，每一个都会受到n个k（资本品供应商）的报价
        :return:
        """
        price_collection = {}
        num_k = int(p.a.degree_of_imperfect_information * len(self.k_firms_id))  # 确定报价数量
        all_ask_price = {k_firm.firm_id: k_firm.ask_price for k_firm in self.k_firms}
        for c_firm in self.c_firms:
            filter_k_firms = random.sample(self.k_firms, num_k)
            price_collection[c_firm.firm_id] = {k.firm_id: all_ask_price[k.firm_id] for k in filter_k_firms}
        return price_collection, all_ask_price

    def update_k_supplier(self):
        contract_book = self.c_firm_supplier_contract_book
        k_firms_bid_price_for_c, all_k_firm_bid_price = self.c_firms_observe_k_firms_price()  # 这个函数一个循环只能调用一次
        for c_firm_id, k_firm_id in contract_book.items():
            contract_ask_price = all_k_firm_bid_price[k_firm_id]
            # 获取竞争者报价清单，要注意竞争者报价在
            other_k_firm_ask_price_collection = k_firms_bid_price_for_c[c_firm_id]
            competitor_firm_id = min(other_k_firm_ask_price_collection, key=other_k_firm_ask_price_collection.get)
            competitor_price = other_k_firm_ask_price_collection[competitor_firm_id]
            # 如果竞争者最低报价小于当前的供应商报价，那么有一定概率切换供应商
            if competitor_price < contract_ask_price:
                if random.random() <= p.a.probability_of_switch:
                    self.c_firm_supplier_contract_book[c_firm_id] = competitor_firm_id

    def format_contract_between_capital_and_consumption_firms(self):
        contract_collection = []
        for c_firm_id, k_firm_id in self.c_firm_supplier_contract_book.items():
            k_firm = self.search_firm_by_id(k_firm_id)
            c_firm = self.search_firm_by_id(c_firm_id)
            price = k_firm.pricing(self.year)
            investment = c_firm.investment
            c_firm.paras['nominal_investment'] = price * investment
            contract = {'c_firm_id': c_firm_id,
                        'k_firm_id': k_firm_id,
                        'price': price,
                        'quantity': investment,
                        'payment': price * investment}
            contract_collection.append(contract)
        return contract_collection


class LaborMarket:
    def __init__(self,
                 gov: Government,
                 c_firms: List[Firms],
                 k_firms: List[Firms],
                 households: List[HouseHolds],
                 ):
        self.gov = gov
        self.dole = p.ratio.ratio_of_dole_to_wage * p.h.households_wage
        self.c_firms: List[Firms] = c_firms
        self.k_firms: List[Firms] = k_firms
        self.all_firms = [*self.c_firms, *self.k_firms]
        self.firms_id = self.all_firm_id()
        self.households: List[HouseHolds] = households
        self.households_id = [h.household_id for h in self.households]
        self.job_contract: List[JobContract] = self.ini_household_employment_status()

    def cal_unemployment_rate(self):
        unemployment_households = [1 for h in self.households if not h.employed_history[-1]]
        return len(unemployment_households) / len(self.households)

    def all_firm_id(self):
        id_all = []
        for c in self.c_firms:
            id_all.append(c.firm_id)
        for k in self.k_firms:
            id_all.append(k.firm_id)
        return id_all

    def get_firm_by_id(self, f_id):
        all_id = [f.firm_id for f in self.all_firms]
        return self.all_firms[all_id.index(f_id)]

    def get_household_by_id(self, h_id):
        return self.households[self.households_id.index(h_id)]

    def ini_household_employment_status(self):

        def set_employment_by_an_entity(c_k_g_u, selected_workers_id, emp_li, entity_type):
            for h_id in selected_workers_id:
                c_k_g_u.worker_list.append(h_id)
                h = self.get_household_by_id(h_id)
                c_k_g_u.wage_list.append(p.h.households_wage)

                if entity_type in ['c', 'k']:
                    employer_id = c_k_g_u.firm_id
                elif entity_type in ['g', 'u']:
                    employer_id = 'gov'

                if entity_type in ['c', 'k', 'g']:
                    h.employed_history = [True, True]
                    wg = p.h.households_wage
                    employed = True
                else:
                    h.employed_history = [False, False]
                    wg = p.h.households_wage * p.ratio.ratio_of_dole_to_wage
                    employed = False

                w_contract = {'wage': wg, 'household_id': h_id, 'employer': employer_id, 'employed': employed}
                emp_li.append(JobContract(w_contract))
            return emp_li

        def ini_employment(firms, hs_id, number_of_workers, entity_type):
            e_status = []
            for firm in firms:
                workers_id = random.sample(hs_id, number_of_workers)
                hs_id = [h_id for h_id in hs_id if h_id not in workers_id]
                e_status = set_employment_by_an_entity(firm, workers_id, e_status, entity_type)
            return hs_id, e_status

        households_id = [h.household_id for h in self.households]
        # 所有k公司雇佣人员的工资和雇佣关系初始化
        number_of_workers_in_k_firm = int(p.w.number_of_capital_firm_workers / p.n.number_of_k_firms)
        households_id, k_emp = ini_employment(self.k_firms, households_id, number_of_workers_in_k_firm, 'k')
        # 所有C公司雇佣人员的工资和雇佣关系初始化
        number_of_workers_in_c_firm = int(p.w.number_of_consumption_firm_workers / p.n.number_of_c_firms)
        households_id, c_emp = ini_employment(self.c_firms, households_id, number_of_workers_in_c_firm, 'c')
        # 所有政府雇员的初始化
        selected_worker_id_of_public = random.sample(households_id, int(p.w.number_of_government_workers))
        households_id = [h_id for h_id in households_id if h_id not in selected_worker_id_of_public]
        g_emp = set_employment_by_an_entity(self.gov, selected_worker_id_of_public, [], 'g')
        # 所有失业人员的初始化
        d_emp = set_employment_by_an_entity(self.gov, households_id, [], 'u')

        return [*c_emp, *k_emp, *g_emp, *d_emp]


class CreditMarkets:
    def __init__(self,
                 year: int,  # 开始年份
                 c_firms: List[Firms],  # 消费品公司Agent集合
                 k_firms: List[Firms],  # 资本品公司Agent集合
                 banks: List[Banks],  # 银行Agent集合
                 households: List[HouseHolds],  # 居民部门Agent集合
                 government: Government,  # 政府Agent
                 central_bank: CentralBank,  # 中央银行Agent
                 firm_match_bank_for_loan: dict,  # 公司与银行的贷款关系
                 households_hold_firm_stocks: dict,  # 居民与公司的股份关系
                 households_hold_bank_stocks: dict,  # 居民与银行的股份关系
                 households_match_deposit_bank: dict,  # 居民与银行的存款关系
                 firms_match_deposit_bank: dict,  # 公司与银行的存款关系
                 ):

        self.year = year
        self.households: List[HouseHolds] = households
        self.c_firms: List[Firms] = c_firms
        self.k_firms: List[Firms] = k_firms
        self.banks: List[Banks] = banks
        self.government: Government = government
        self.central_bank: CentralBank = central_bank

        self.cash_advance_interest_rate = p.ir.interest_rate_of_advances  # 初始化预借款率
        self.bonds_interest_rate = p.ir.interest_rate_of_bonds  # 初始化债券利率

        self.banks_id = [bank.bank_id for bank in self.banks]  # 银行id列表
        self.households_id = [h.household_id for h in self.households]  # 居民id列表

        self.firms_matching_bank_for_loan = firm_match_bank_for_loan  # 公司与银行的贷款关系
        self.households_own_firms_book = households_hold_firm_stocks  # 居民持有公司股份
        self.households_own_banks_book = households_hold_bank_stocks  # 居民持有银行股份
        self.households_matching_bank_for_deposit = households_match_deposit_bank  # 居民的存款银行
        self.firms_matching_bank_for_deposit = firms_match_deposit_bank  # 公司的存款银行

        self.households_deposit_contract = self.ini_household_deposit_contract()  # 初始化居民存款合同
        self.firms_deposit_contract = self.ini_firm_deposit_contract()  # 初始化公司存款合同

        self.government_bond_contract = self.ini_government_bond_contract()  # 初始化债券合约
        self.bank_cash_advance_contract = self.ini_bank_cash_advance_contract()  # 初始化预借款合约

    def ini_household_deposit_contract(self):
        """
        初始化居民和银行的存款合同，合同内容包括bank_id,household_id,amount,interest_rate,interest_per_year,text
        :return:
        """
        contracts = []
        for h in self.households:
            bank_id = self.households_matching_bank_for_deposit[h.household_id]
            bank = self.search_bank_by_id(bank_id)
            deposit_contract = {
                'bank_id': bank_id,
                'household_id': h.household_id,
                'amount': h.deposits,
                'interest_rate': bank.deposit_interest_rate,
                'interest_per_year': h.deposits * bank.deposit_interest_rate,
                'text': f"居民{h.household_id}存在银行{bank_id}存款金额为{h.deposits},利率为{bank.deposit_interest_rate}"
            }
            contracts.append(deposit_contract)
        return contracts

    def ini_firm_deposit_contract(self):
        """
        初始化公司存款合同，合同内容包括bank_id,firm_id,amount,interest_rate,interest_per_year,text
        :return:
        """
        contracts = []
        for firms in [self.c_firms, self.k_firms]:
            for firm in firms:
                bank_id = self.firms_matching_bank_for_deposit[firm.firm_id]
                bank = self.search_bank_by_id(bank_id)
                deposit_contract = {
                    'bank_id': bank_id, 'firm_id': firm.firm_id, 'amount': firm.deposits,
                    'interest_rate': bank.deposit_interest_rate,
                    'interest_per_year': firm.deposits * bank.deposit_interest_rate,
                    'text': f"公司{firm.firm_id}存在银行{bank_id}存款金额为{firm.deposits},利率为{bank.deposit_interest_rate}"
                }
                firm.deposits_contract = DepositContract(deposit_contract)
                contracts.append(deposit_contract)
        return contracts

    def ini_government_bond_contract(self):
        """
        初始化政府债券合同，持有者分别为中央银行和商业银行，
        合同内容包括bank_id,amount,interest_rate,issue_year,total_year,remaining_year，
        单个银行持有的初始化债券金额为：INI_BANK_BONDS，利率为INI_INTEREST_RARE_OF_BOND
        :return:
        """
        bond_contracts = {'bank': [], 'cb_bank': []}
        for bank in self.banks:
            bank_id = bank.bank_id
            loan_contract = {'bank_id': bank_id, 'amount': bank.bonds,
                             'interest_rate': p.ir.interest_rate_of_bonds, 'issue_year': self.year,
                             'total_year': 20, 'remaining_year': 20}
            bond_contracts['bank'].append(loan_contract)
        cb_contract = {'bank_id': 'central_bank', 'amount': self.central_bank.bonds,
                       'interest_rate': p.ir.interest_rate_of_bonds, 'issue_year': self.year,
                       'total_year': 20, 'remaining_year': 20}
        bond_contracts['cb_bank'].append(cb_contract)
        return bond_contracts

    def ini_bank_cash_advance_contract(self):
        """
        初始化银行与中央银行的现金预借款合同，合同内容包括：bank_id,amount,interest_rate
        :return:
        """
        cash_advance_contract = []
        for bank in self.banks:
            bank_id = bank.bank_id
            loan_contract = {'bank_id': bank_id,
                             'amount': bank.cash_advance,
                             'interest_rate': self.cash_advance_interest_rate}
            cash_advance_contract.append(loan_contract)
        return cash_advance_contract

    def credit_demand_and_supplier(self):
        """
        企业部门分别汇总其信贷需求，通过Firms.finance方法来实现，
        :return: dict，key：firm_id value:finance
        """
        finance = {'c': {c.firm_id: c.finance for c in self.c_firms},
                   'k': {k.firm_id: k.finance for k in self.k_firms}, }
        return {**finance['c'], **finance['k']}

    def search_firm_by_id(self, firm_id) -> Firms:
        """
        通过id找到公司的实体
        :param firm_id:
        :return:
        """
        for k_firm in self.k_firms:
            if k_firm.firm_id == firm_id:
                return k_firm
        for c_firm in self.c_firms:
            if c_firm.firm_id == firm_id:
                return c_firm

    def search_bank_by_id(self, bank_id) -> Banks:
        """
        通过id找到银行的实体
        :param bank_id:
        :return:
        """
        for bank in self.banks:
            if bank.bank_id == bank_id:
                return bank

    def search_household_by_id(self, household_id) -> HouseHolds:
        """
        通过id找到居民的实体
        :param household_id:
        :return:
        """
        for h in self.households:
            if h.household_id == household_id:
                return h

    def credit_supply(self, demand_and_supplier) -> List:
        """
        信贷供应，通过汇总公司的信贷需求，银行决定房贷情况，形成合同
        :param demand_and_supplier:
        :return:
        """
        for firm_id, loan_demand in demand_and_supplier.items():
            bank_id = self.firms_matching_bank_for_loan[firm_id]
            loan_bank = self.search_bank_by_id(bank_id)
            firm = self.search_firm_by_id(firm_id)

            contract = {'amount': loan_demand, 'interest_rate': loan_bank.loan_interest_rate, 'firm_id': firm.firm_id,
                        'contract_year': self.year, 'left_year': p.para.duration_or_loan + 1,
                        'bank_id': loan_bank.bank_id}

            firm.batch_of_loan_contracts.insert(0, LoanContract(contract))
            firm.deposits += loan_demand
            firm.loans += loan_demand
            firm_deposit_bank_id = firm.deposits_bank_id

            deposit_bank = self.search_bank_by_id(firm_deposit_bank_id)
            deposit_bank.deposits += loan_demand
            loan_bank.loans += loan_demand
            # 银行跨行转账通过中央银行清算
            loan_bank.reserves -= loan_demand
            deposit_bank.reserves += loan_demand

    def households_observe_deposits_interests_rate(self):
        """
        居民部门观察存款利率市场各银行的报价
        :return:
        """
        price_collection = {}
        num_b = int(p.a.degree_of_imperfect_information * len(self.banks_id))  # 确定报价数量
        all_ask_interest_rate = {b.bank_id: b.deposit_interest_rate for b in self.banks}
        for h in self.households:
            filter_banks = random.sample(self.banks, num_b)
            price_collection[h.household_id] = {b.bank_id: all_ask_interest_rate[b.bank_id] for b in filter_banks}
        return price_collection, all_ask_interest_rate

    def update_household_deposits_bank(self):
        """
        居民根据所见到的不同银行的报价，决定是否切换自己的存款银行
        :return:
        """
        contract_book = self.households_matching_bank_for_deposit
        banks_bid_interest_rate_for_households, all_bids = self.households_observe_deposits_interests_rate()
        for household_id, bank_id in contract_book.items():
            contract_interest_rate = all_bids[bank_id]
            # 获取竞争者银行的利率清单，要注意竞争者报价在
            other_bank_interest_rate = banks_bid_interest_rate_for_households[household_id]
            competitor_bank_id = max(other_bank_interest_rate, key=other_bank_interest_rate.get)  # 获取竞争者id
            competitor_interest_rate = other_bank_interest_rate[competitor_bank_id]
            # 如果竞争者存款利率高于当前签约银行的存款利率，那么有一定概率切换供应商
            if competitor_interest_rate > contract_interest_rate:
                if random.random() <= p.a.probability_of_switch:
                    self.households_matching_bank_for_deposit[household_id] = competitor_bank_id


class Events:
    def __init__(self,
                 government: Government,
                 central_bank: CentralBank,
                 credit_markets: CreditMarkets,
                 consumption_markets: ConsumptionGoodsMarket,
                 capital_markets: CapitalGoodsMarket,
                 labor_markets: LaborMarket,
                 year,
                 ):
        self.year = year
        self.gov: Government = government
        self.cb: CentralBank = central_bank
        # 消费品市场
        self.consumption_goods_market: ConsumptionGoodsMarket = consumption_markets
        # 资本品市场
        self.capital_goods_market: CapitalGoodsMarket = capital_markets
        # 信贷市场
        self.credit_market: CreditMarkets = credit_markets
        # 就业市场
        self.labor_market: LaborMarket = labor_markets
        # gov
        self.gov_collect_tax_amount = 0  # 占位，后期在每一个循环中赋值，政府收税
        self.gov_payment_of_wages_and_doles = 0  # 政府支付工资和救济金
        self.gov_payment_of_bond_interests = 0
        # bank
        self.bank_payment_of_cash_advance_interests = 0
        # central bank
        self.cb_collect_bonds_interests = 0
        self.cb_collect_cash_advance_interests = 0
        self.transaction_flow = {}

    # 0 update new state
    def update_new_state(self):
        for c in self.credit_market.c_firms:
            c.update_new_period()
        for k in self.credit_market.k_firms:
            k.update_new_period()

    # 1 production planning 制定生产计划
    def production_planning(self):
        """
        对于c和k公司，制定生产计划，生产计划制定与预期销量，存货持有意愿与期初存货情况有关。
        :return:
        """
        for c in self.credit_market.c_firms:
            c.output_decision()
        for k in self.credit_market.k_firms:
            k.output_decision()

    # 2 labor_demand 劳动力需求
    def labor_demand(self):
        """
        对于c和k公司，根据最新的生产计划（1），预计需要的工人（居民部门），不同部门计算方式不一样，
        对于k公司来说，就是y与劳动生产率决定的，对于c公司还要考虑资本存量
        :return:
        """
        for c in self.labor_market.c_firms:
            c.needed_works()
        for k in self.labor_market.k_firms:
            k.needed_works()

    # 3.1 pricing 定价
    def pricing(self):
        """
        企业如何定价，对于c和k公司来说，按照后凯恩斯主义一些经济学家的框架，按照平均成本加成定价。
        :param year:
        :return:
        """
        year = self.year
        for c in self.credit_market.c_firms:
            c.pricing(year)
        for k in self.credit_market.k_firms:
            k.pricing(year)

    # 3.2 bank set_interests_of_loans_and_deposits 银行设定贷款利率和存款利率
    def set_interests_of_loans_and_deposits(self):
        """
        银行设定贷款利率和存款利率。
        银行设置存款利率，跟自身的liquidity_ratio有关，如果超过target，说明银行存款准备金过多，降低存款利率
        银行如何设置贷款利率，跟自身的capital_ratio有关，如果超过target，说明净值/贷款过高，贷款利率要下行
        :return:
        """
        for b in self.credit_market.banks:
            b.set_loan_interest_rate()
            b.set_deposit_interest_rate()

    # 3.3 works ask their wages 工人提出新的工资需求
    def works_ask_wages(self, unemployment_rate):
        """
        :param unemployment_rate: 工人根据失业率情况来确定自己的工资要求
        :return:
        """
        for jb_contract in self.labor_market.job_contract:
            if jb_contract.employed:
                h = self.credit_market.search_household_by_id(jb_contract.household_id)
                new_wages = h.update_wages_contract(unemployment_rate)
                jb_contract.wage = new_wages

    # 4 desired rate of capacity growth, real demand for capital goods 企业设定对投资品的需求
    # 5 Capital good market (1): consumption firms choose their capital supplier 资本品市场，消费品公司选择资本品供应商
    def update_capital_supplier(self):
        self.capital_goods_market.update_k_supplier()
        # 形成合同，合同包含交易双方id，交易数量，价格，后续确定转账情况
        contract_collection = self.capital_goods_market.format_contract_between_capital_and_consumption_firms()
        return contract_collection

    # 6 Credit demand（Credit Market) 信贷市场，公司选择贷款银行
    def credit_demand(self):
        return self.credit_market.credit_demand_and_supplier()

    # 7 Credit supply 信贷市场，银行就公司信贷需求签合同
    def credit_supply(self, demand_and_supplier):
        self.credit_market.credit_supply(demand_and_supplier)

    # 8 Labor market for unemployed 劳动力市场，签合同
    def unemployed_workers_interact_with_firms(self, unemployment_rate):
        for jb_contract in self.labor_market.job_contract:
            if not jb_contract.employed:
                h = self.credit_market.search_household_by_id(jb_contract.household_id)
                h.update_wages_contract(unemployment_rate)

    # 9 Production 生产过程 劳动力市场，支付工资
    def production(self):
        for c_firm in self.credit_market.c_firms:
            c_firm.production()
        for k_firm in self.credit_market.k_firms:
            k_firm.production()

    # 10 capital goods market 2
    def execute_a_capital_goods_contract(self, contract):
        """
        'c_firm_id' 'k_firm_id' 'price' 'quantity'
        :return:
        """
        c_firm = self.capital_goods_market.search_firm_by_id(contract['c_firm_id'])
        k_firm = self.capital_goods_market.search_firm_by_id(contract['k_firm_id'])
        quantity = min(contract['quantity'], k_firm.inventory)
        money = contract['price'] * quantity
        k_firm.sales_list.append(money)
        LOGG[str(uuid.uuid4())] = {"k": k_firm.firm_id, 'c': c_firm.firm_id, 'k_h': money, 'c_h': -money,
                                   'log': "出售资本品"}

        k_firm.inventory -= quantity

        k_firm.inventory_end = k_firm.inventory
        c_firm.capital += quantity

        c_firm.deposits -= money
        k_firm.deposits += money

        bank_c = self.credit_market.search_bank_by_id(c_firm.deposits_bank_id)
        bank_k = self.credit_market.search_bank_by_id(k_firm.deposits_bank_id)
        bank_c.reserves -= money
        bank_c.deposits -= money
        bank_k.reserves += money
        bank_k.deposits += money

    def execute_capital_goods_contract(self, contracts):
        for contract in contracts:
            self.execute_a_capital_goods_contract(contract)

    # 11. Consumption goods market
    def execute_a_consumption_goods_contract(self, contract):
        """
        'household_id' 'c_firm_id' 'price' 'payment'
        :param contract:
        :return:
        """
        c_firm = self.consumption_goods_market.search_c_firm_by_id(contract.c_firm_id)
        household = self.consumption_goods_market.search_household_by_id(contract.household_id)
        nominal_payment = contract.quantity * contract.price  # 消费品的交易金额
        c_firm.sales_list.append(nominal_payment)
        c_firm.inventory -= contract.quantity

        # household eat or consume quantity
        c_firm.deposits += nominal_payment
        household.deposits -= nominal_payment

        bank_c = self.credit_market.search_bank_by_id(c_firm.deposits_bank_id)
        bank_h = self.credit_market.search_bank_by_id(household.deposits_bank_id)
        bank_c.deposits += nominal_payment
        bank_c.reserves += nominal_payment
        bank_h.deposits -= nominal_payment
        bank_h.reserves -= nominal_payment
        return nominal_payment

    def execute_consume(self):
        payment_li = []
        year = self.credit_market.year
        contracts = self.consumption_goods_market.format_contract_between_c_firms_and_households(year)
        for contract in contracts:
            payment = self.execute_a_consumption_goods_contract(contract)
            payment_li.append(payment)
        for c_firm in self.credit_market.c_firms:
            c_firm.paras['inventory'] = c_firm.inventory
        self.transaction_flow['consumption'] = {'amount': sum(payment_li), 'detail': payment_li}

    # 12. loans and interests repayment
    def loan_and_interests_repayment(self):
        """
        'bank_id', 'firm_id', 'amount', 'interest_rate', 'taken_year', 'total_year', 'remaining_year',
        'repayment_per_year'
        :return:
        """
        for firm in [*self.credit_market.c_firms, *self.credit_market.k_firms]:
            loan_contracts = firm.batch_of_loan_contracts
            for loan_contract in loan_contracts:
                # 这个是为了过滤掉刚刚贷出来的钱，不用还款，也不用还利息
                if loan_contract.left_year <= p.para.duration_or_loan:
                    loan_bank = self.credit_market.search_bank_by_id(loan_contract.bank_id)
                    interests_payment = loan_contract.amount * loan_contract.interest_rate
                    principal_payment = loan_contract.amount / loan_contract.left_year

                    deposit_bank = self.credit_market.search_bank_by_id(firm.deposits_bank_id)

                    for repayment in [interests_payment, principal_payment]:
                        loan_bank.reserves += repayment
                        deposit_bank.reserves -= repayment

                        firm.deposits -= repayment
                        deposit_bank.deposits -= repayment

                    loan_bank.loans -= principal_payment
                    firm.loans -= principal_payment
                    loan_contract.amount -= principal_payment

                loan_contract.left_year -= 1  # 贷款期限还有10年的，过了一年，所以还剩下9年，同理，1年的，已经截止了

            loan_contracts.pop()  # 要删除最后一个还完本金的贷款

    # 12 deposit interests payment
    def deposit_interests_payment(self):
        """
        对存款支付利息
        'bank_id', 'household_id', 'amount', 'interest_rate', 'start_year', 'contract_year', 'remaining_year',
        'interest_per_year'
        :return:
        """
        for contract in self.credit_market.households_deposit_contract:
            bank = self.credit_market.search_bank_by_id(contract['bank_id'])
            household = self.credit_market.search_household_by_id(contract['household_id'])
            interests_amount = contract['interest_per_year']

            bank.deposits += interests_amount
            household.deposits += interests_amount
            bank.reserves -= interests_amount
            self.cb.reserves -= interests_amount

        for contract in self.credit_market.firms_deposit_contract:
            bank = self.credit_market.search_bank_by_id(contract['bank_id'])
            firm = self.credit_market.search_firm_by_id(contract['firm_id'])

            interests_amount = contract['interest_per_year']

            firm.get_deposits_interests = interests_amount
            bank.deposits += interests_amount
            firm.deposits += interests_amount
            bank.reserves -= interests_amount
            self.cb.reserves -= interests_amount

    # 12 deposit interests payment
    def bond_interests_payment(self):
        """
        'bank_id', 'amount', 'interest_rate', 'issue_year', 'total_year', 'remaining_year'
        :return:
        """
        total_payment = 0
        cb_collect_payment = 0
        bank_holds_bond = self.credit_market.government_bond_contract['bank']
        cb_bank_holds_bond = self.credit_market.government_bond_contract['cb_bank']
        for contract in bank_holds_bond:
            bank = self.credit_market.search_bank_by_id(contract['bank_id'])
            interest_amount = contract['interest_rate'] * contract['amount']
            total_payment += interest_amount
            bank.reserves += interest_amount
            bank.bonds_interests_payment = interest_amount  # 给类内赋值，后续计算利润和股利会遇到
            self.gov.deposits -= interest_amount
            self.cb.treasury_deposits -= interest_amount
            self.cb.reserves += interest_amount

        for contract in cb_bank_holds_bond:
            interest_amount = contract['interest_rate'] * contract['amount']
            total_payment += interest_amount
            cb_collect_payment += interest_amount
            self.gov.deposits -= interest_amount
            self.cb.treasury_deposits -= interest_amount

        self.gov_payment_of_bond_interests = total_payment
        self.cb_collect_bonds_interests = cb_collect_payment

    def cash_advance_and_interests_payment(self):
        sum_interests = 0
        for contract in self.credit_market.bank_cash_advance_contract:
            interest_amount = contract['interest_rate'] * contract['amount']
            repayment = contract['amount']
            sum_interests += interest_amount
            bank = self.credit_market.search_bank_by_id(contract['bank_id'])
            # 归还利息
            bank.reserves -= interest_amount
            self.cb.reserves -= interest_amount
            # 归还本金
            bank.reserves -= repayment
            self.cb.reserves -= repayment

        self.bank_payment_of_cash_advance_interests = sum_interests

    # 13. wage and dole
    def pay_wages_and_dole(self):
        gov_wages_li = []
        gov_doles_li = []
        for contract in self.labor_market.job_contract:
            wage = contract.wage
            household = self.credit_market.search_household_by_id(contract.household_id)
            bank_household_deposit = self.credit_market.search_bank_by_id(household.deposits_bank_id)
            if contract.employer == 'gov':
                if household.employed_history[-1]:
                    gov_wages_li.append(wage)
                else:
                    gov_doles_li.append(wage)
                household.deposits += wage  # 居民银行账户增加
                # 银行负债（居民存款增加），银行资产（准备金）增加，
                bank_household_deposit.deposits += wage  # 居民存钱的银行，存款负债增加
                bank_household_deposit.reserves += wage  # 居民存钱的银行，存款准备金增加
                # 央行资产负债表中，财政存款（负债）减少，存款准备金（负债）增加，一增一减
            else:
                firm = self.credit_market.search_firm_by_id(contract.employer)
                firm.deposits -= wage
                firm.payment_of_wages_list.append(wage)
                household.deposits += wage
                bank_firm_deposit = self.credit_market.search_bank_by_id(firm.deposits_bank_id)

                bank_firm_deposit.reserves -= wage
                bank_firm_deposit.deposits -= wage

                bank_household_deposit.reserves += wage
                bank_household_deposit.deposits += wage

        prt('政府存款', self.gov.deposits)
        gov_wages = sum(gov_wages_li)
        gov_doles = sum(gov_doles_li)
        wages_and_doles = gov_wages + gov_doles
        self.gov.deposits -= wages_and_doles
        self.cb.treasury_deposits -= wages_and_doles  # 央行的财政存款账户减少（央行负债）
        self.cb.reserves += wages_and_doles  # 央行的存款准备金（央行负债）
        prt('政府', self.gov.deposits, '工资', gov_wages, len(gov_wages_li), '救济金', gov_doles, len(gov_doles_li))
        self.gov_payment_of_wages_and_doles = wages_and_doles  # 政府为其资金缺口融资的时候要用

    # 14. tax
    def household_pay_tax(self):
        h_tax_li = []
        for h in self.labor_market.households:
            tax = h.wages * p.ratio.tax_rate
            h.deposits -= tax
            deposit_bank = self.credit_market.search_bank_by_id(h.deposits_bank_id)
            deposit_bank.deposits -= tax
            deposit_bank.reserves -= tax
            h_tax_li.append(tax)
        h_tax_all = sum(h_tax_li)
        self.gov.deposits += h_tax_all
        self.cb.reserves -= h_tax_all  # 中央银行存款准备金负债减少
        self.cb.treasury_deposits += h_tax_all  # 中央银行财政存款负债增加，维持净负债不变
        prt('居民部门交税', h_tax_all, '政府财政存款', self.gov.deposits)
        return sum(h_tax_li)

    def firm_pay_tax(self, c=True):
        if c:
            firms = self.credit_market.c_firms
        else:
            firms = self.credit_market.k_firms
        tax_li = []
        for f in firms:
            tax = f.profits(expected=False) * p.ratio.tax_rate
            f.deposits -= tax
            tax_li.append(tax)
            bank = self.credit_market.search_bank_by_id(f.deposits_bank_id)
            bank.deposits -= tax
            bank.reserves -= tax
        f_tax_all = sum(tax_li)
        self.gov.deposits += f_tax_all
        self.cb.reserves -= f_tax_all
        self.cb.treasury_deposits += f_tax_all
        prt('企业部门交税', f.firm_id, f_tax_all, '政府财政存款', self.gov.deposits)
        return f_tax_all

    def bank_pay_tax(self):
        tax_li = []
        for bank in self.credit_market.banks:
            profits = bank.profits
            tax = profits * p.ratio.tax_rate
            tax_li.append(tax)
            bank.reserves -= tax
        b_tax_all = sum(tax_li)
        self.gov.deposits += b_tax_all
        self.cb.reserves -= b_tax_all
        self.cb.treasury_deposits += b_tax_all
        return b_tax_all

    def gov_collect_tax(self):
        household_tax = self.household_pay_tax()
        c_firm_tax = self.firm_pay_tax(c=True)
        k_firm_tax = self.firm_pay_tax(c=False)
        bank_tax = self.bank_pay_tax()
        self.gov_collect_tax_amount = household_tax + c_firm_tax + k_firm_tax + bank_tax
        print('收税之后', self.gov.deposits, '政府存款')

    # 15 Dividends
    def firm_pay_dividends(self):
        stock_holder_book = self.credit_market.households_own_firms_book
        for firm_id, firm_stockholders in stock_holder_book.items():
            firm = self.credit_market.search_firm_by_id(firm_id)
            bank_of_firm = self.credit_market.search_bank_by_id(firm.deposits_bank_id)
            dividends = firm.dividends
            dividends_per_household = dividends / p.a.average_stockholder_per_firm
            for household_id in firm_stockholders:
                household = self.credit_market.search_household_by_id(household_id)

                household.deposits += dividends_per_household  # 居民收到股利
                firm.deposits -= dividends_per_household

                bank_of_household = self.credit_market.search_bank_by_id(household.deposits_bank_id)

                bank_of_firm.deposits -= dividends_per_household
                bank_of_firm.reserves -= dividends_per_household

                bank_of_household.deposits += dividends_per_household
                bank_of_household.reserves += dividends_per_household

    def bank_pay_dividends(self):
        stock_holder_book = self.credit_market.households_own_banks_book
        for bank_id, bank_stockholders in stock_holder_book.items():
            bank = self.credit_market.search_bank_by_id(bank_id)
            dividends = bank.dividends
            dividends_per_household = dividends / p.a.average_stockholder_per_firm
            for household_id in bank_stockholders:
                household = self.credit_market.search_household_by_id(household_id)

                household.deposits += dividends_per_household  # 居民收到股利
                bank.reserves -= dividends_per_household

                bank_of_household = self.credit_market.search_bank_by_id(household.deposits_bank_id)
                bank_of_household.deposits += dividends_per_household
                bank_of_household.reserves += dividends_per_household

                # 中央银行的银行存款负债一增一减，保持不变

    # 16. deposit market interaction
    def agent_renew_their_deposit_bank(self):
        household_match_bank_old = self.credit_market.households_matching_bank_for_deposit
        self.credit_market.update_household_deposits_bank()
        for household_id, new_bank_id in self.credit_market.households_matching_bank_for_deposit.items():
            old_bank_id = household_match_bank_old[household_id]
            household = self.credit_market.search_household_by_id(household_id)
            new_bank = self.credit_market.search_bank_by_id(new_bank_id)
            if new_bank_id != old_bank_id:
                household.deposits_bank_id = new_bank_id
                transfer_deposits = household.deposits
                # 如果居民因为存款利率市场，改变了自己的存款银行，那么其存款就要从老银行搬家到新银行
                new_bank.deposits += transfer_deposits
                new_bank.reserves += transfer_deposits
                old_bank = self.credit_market.search_bank_by_id(old_bank_id)
                old_bank.deposits -= transfer_deposits
                old_bank.reserves -= transfer_deposits

    # 17. Bank and Central Bank purchase newly issued bonds
    def gov_need_issue_bonds(self):
        # 银行需要新发债券等于 税收 + 央行利润 - 工资 - 救济金 - 债券利息
        cb_profits = self.cb_collect_bonds_interests + self.cb_collect_cash_advance_interests
        input_money = self.gov_collect_tax_amount + cb_profits
        output_money = self.gov_payment_of_wages_and_doles + self.gov_payment_of_bond_interests
        need_issue_bonds = input_money + cb_profits - output_money
        return need_issue_bonds

    def bank_and_central_bank_purchase_bonds(self):
        bonds_need_issue = self.gov_need_issue_bonds()
        bonds_left = self.bank_buy_issue_bonds_from_gov(bonds_need_issue)
        if bonds_left > 1:
            self.cb_buy_issue_bonds_from_gov(bonds_left, self.credit_market.bonds_interest_rate)

    def bank_buy_issue_bonds_from_gov(self, bonds_amount):
        available_collection = {}
        for bank in self.credit_market.banks:
            available_collection[bank.bank_id] = bank.available_money_for_buy_bonds()
        sum_money = sum([v for k, v in available_collection.items()])
        correction_v = sum_money / bonds_amount
        if sum_money < bonds_amount:  # 如果银行的总债券购买额度小于政府拟发行量
            available_collection = {bank_id: correction_v * v for bank_id, v in available_collection.items()}
        else:
            available_collection = {bank_id: v / correction_v for bank_id, v in available_collection.items()}
        for bank_id, bank_buy_bonds in available_collection.items():
            bank = self.credit_market.search_bank_by_id(bank_id)
            # 银行购买政府新发行国债，那么银行资产中债券增加，保证金存款减少
            bank.bonds += bank_buy_bonds
            bank.reserves -= bank_buy_bonds
            bonds_amount -= bank_buy_bonds
            # 政府发行国债后，其负债方面，国债增加，其财政存款增加
            self.gov.deposits += bank_buy_bonds
            self.gov.bonds += bank_buy_bonds
            # 对于央行来说 其负债财政存款增加，其另一方面对银行的负债，保证金减少
            self.cb.treasury_deposits += bank_buy_bonds
            self.cb.reserves -= bank_buy_bonds
        return bonds_amount

    def cb_buy_issue_bonds_from_gov(self, amount, interest_rate):
        """
        央行购买财政部发行的债券，对于央行来说，其资产负债表中，资产方：持有政府债权增加，负债方，财政存款增加
        对于政府来说，其资产方财政存款增加，其负债方，债券
        :param amount:
        :param interest_rate:
        :return:
        """
        bonds_detail = {'amount': amount, 'id': '', 'interest_rate': interest_rate}
        self.cb.bonds_collection.append(bonds_detail)
        self.cb.bonds += amount  # 中央银行资产（持有政府债券）增加
        self.cb.treasury_deposits += amount  # 财政存款增加（银行借到了钱存到了央行的财政账户）
        self.gov.bonds_collection.append(bonds_detail)
        self.gov.bonds += amount  # 政府发行债券，其资产负债表负债增加了一笔
        print('gov deposits', self.gov.deposits, 'cb_buy')
        self.gov.deposits += amount  # 政府发行债券后，还没有花钱的过程中，其存款增加了一部
        print('gov deposits', self.gov.deposits)

    # 18. Central Bank accommodates cash advances requests by private bank
    def bank_ask_for_cash_advance(self):  # 银行向央行短期借款 to restore the mandatory liquidity ratio
        for bank in self.credit_market.banks:
            need_cash_advance = bank.ask_for_cash_advance()
            if need_cash_advance > 0:
                bank.reserves += need_cash_advance
                bank.cash_advance = need_cash_advance

                self.cb.reserves += need_cash_advance
                self.cb.cash_advances += need_cash_advance

    def update_state_of_agents(self):
        self.capital_goods_market.k_supplier_update_state()

    def run_a_episode(self):
        # 1. Production planning: consumption and capital firms compute their desired output level.
        # 1.生产计划
        self.production_planning()
        # 2. Firms' labor demand: firms evaluate the number of workers needed to produce. 公司劳动力需求
        self.labor_demand()
        # 3. Prices, interest, and Wages: consumption and capital firms set the price of their output;
        self.pricing()
        #  banks determine the interest rate on loans and deposits. Workers adaptively revise their reservation wages.
        self.set_interests_of_loans_and_deposits()
        # 居民部门设定自身需求的工资
        self.works_ask_wages(self.labor_market.cal_unemployment_rate())
        # 4. Investment in capital accumulation: consumption firms' determine their desired rate of capacity growth and,
        #    as a consequence, their real demand for capital goods.
        # 5. Capital good market (1): consumption firms choose their capital supplier.
        contract_of_capital_goods = self.update_capital_supplier()
        # 6. Credit demand: Firms assess their demand for credit and select the lending bank.
        credit_demand = self.credit_demand()
        # 7. Credit supply: Banks evaluate loan requests and supply credit accordingly.
        self.credit_supply(credit_demand)
        # 8. Labor market: unemployed workers interact with firms on the labor market.
        self.unemployed_workers_interact_with_firms(self.labor_market.cal_unemployment_rate())  # 后期要改
        # 9. Production: capital and consumption firms produce their output.
        self.production()
        # 10. Capital goods market (2): consumption firms purchase capital from their supplier.
        #     New machines are employed in the production process starting from the next period.
        self.execute_capital_goods_contract(contract_of_capital_goods)
        # 11. Consumption goods market: households interact with consumption firms and consume.
        self.execute_consume()
        # 12. Interest, bonds and loans repayment: firms pay interests on loans and repay a (constant) share of each
        #     loan principal. The government repays bonds and interest to bonds' holders. Banks pay interest on deposits
        #     Cash advances and related interests, when present, are repaid.
        self.loan_and_interests_repayment()
        self.deposit_interests_payment()
        self.bond_interests_payment()
        self.cash_advance_and_interests_payment()
        # 13. Wages and dole: wages are paid. Unemployed workers receive a dole from the government.
        self.pay_wages_and_dole()
        # 14. Taxes: taxes on profits and income are paid to the government.
        self.gov_collect_tax()
        # 15. Dividends: dividends are distributed to households.
        self.firm_pay_dividends()
        self.bank_pay_dividends()
        # 16. Deposit market interaction: households and firms select their deposit bank.
        self.agent_renew_their_deposit_bank()
        # 17. Bond purchases: banks and the Central Bank purchase newly issued bonds.
        self.bank_and_central_bank_purchase_bonds()
        # 18. Cash Advances: the Central Bank accommodates cash advances requests by private banks.
        self.bank_ask_for_cash_advance()

        self.year += 1
        self.credit_market.year += 1
        prt("episode Done!")


def ini_household_agents():
    """
    初始化居民群体，分配其id（household_id），工资（wages）, 存款(deposits), 近期就业状态(employ_history)
    :return:
    """
    households = []
    h_i = 0
    deposits = p.h.deposits_of_households / p.w.number_of_households  # 初始化存款
    for i in range(int(p.w.number_of_households)):
        household_id = f"household_{h_i}"  # 身份编码
        household = HouseHolds(ini_id=household_id, ini_deposit=deposits)
        households.append(household)
        h_i += 1
    # 后续还需要确定，居民的存款银行，居民的消费企业，居民持有公司，银行的股份
    return households


def ini_firms_agents(firm_type):
    """
    初始化公司群体，分为两种公司，一种是消费品公司Consumer Goods（c） 另一种是 Capital Goods（k）
    初始化公司的各种数学，如id（firm_id）,公司类型（firm_type）,存货数量（ini_inventory),单位成本（unit_cost),存款（deposits）,
    贷款（loans）
    :param firm_type:
    :return:
    """
    if firm_type == 'Consumer Goods':
        number_of_c_k_firms = p.n.number_of_c_firms
    else:
        number_of_c_k_firms = p.n.number_of_k_firms
    firms = []
    for i in range(number_of_c_k_firms):
        if firm_type == 'Consumer Goods':
            deposits = p.c.deposits_consumption_firm_holds / p.n.number_of_c_firms
            loans = p.c.loans_of_consumption_firms / p.n.number_of_c_firms
            firm_id = f"firm_c_{i}"
            amortization = p.c.amortization_of_consumption_firms / p.n.number_of_c_firms
            unit_cost = p.c.unit_cost_of_consumption_firm
            inv = p.c.consumption_firm_inventory / p.n.number_of_c_firms
            capital = p.c.capital_of_consumption_firm / p.n.number_of_c_firms
        else:
            deposits = p.k.deposits_capital_firms_holds / p.n.number_of_k_firms
            loans = p.k.loans_of_capital_firms / p.n.number_of_k_firms
            firm_id = f"firm_k_{i}"
            unit_cost = p.k.unit_cost_of_capital_firm
            inv = p.k.capital_firm_inventory / p.n.number_of_k_firms
            capital = 0
            amortization = 0
        firm = Firms(ini_id=firm_id,
                     firm_type=firm_type,
                     ini_inventory=inv,
                     ini_unit_cost=unit_cost,
                     ini_deposits=deposits,
                     ini_loans=loans,
                     ini_capital=capital,
                     ini_amortization=amortization)
        firms.append(firm)
    return firms


def ini_bank_agents():
    """
    初始化银行agent，包括id，准备金，贷款，银行持有债券，存款，银行向中央银行的预借款
    :return:
    """
    total_deposits = p.h.deposits_of_households + p.c.deposits_consumption_firm_holds + p.k.deposits_capital_firms_holds
    deposits = total_deposits / p.n.number_of_banks
    loans = (p.c.loans_of_consumption_firms + p.k.loans_of_capital_firms) / p.n.number_of_banks
    banks = []
    for i in range(p.n.number_of_banks):
        bank_id = f"bank_{i}"
        bank_agent = Banks(ini_id=bank_id,
                           ini_reserves=p.b.bank_reserves / p.n.number_of_banks,
                           ini_loans=loans,
                           ini_bonds=p.b.bank_hold_bonds / p.n.number_of_banks,
                           ini_deposits=deposits,
                           ini_cash_advance=0,
                           )
        banks.append(bank_agent)
    return banks


def ini_household_and_firm_matching_bank_for_deposit(households, c_firms, k_firms):
    """
    初始化存款网络客户关系
    :param households: [居民Agent，]
    :param c_firms: [公司Agent]
    :param k_firms: [公司Agent]
    :return: household_match_bank记录了居民的存款银行，key为居民id，value为银行id
             firms_matching_bank 记录了公司的存款银行，key为公司id，value为银行id
    """
    household_matching_bank = {}
    firms_matching_bank = {}
    banks_id = [f"bank_{i}" for i in range(p.n.number_of_banks)]
    for household in households:
        bank_id = random.choice(banks_id)
        household_matching_bank[household.household_id] = bank_id
        household.deposits_bank_id = bank_id
    for c_firm in c_firms:
        bank_id = random.choice(banks_id)
        firms_matching_bank[c_firm.firm_id] = bank_id
        c_firm.deposits_bank_id = bank_id
    for k_firm in k_firms:
        bank_id = random.choice(banks_id)
        firms_matching_bank[k_firm.firm_id] = bank_id
        k_firm.deposits_bank_id = bank_id
    return households, c_firms, k_firms, household_matching_bank, firms_matching_bank


def ini_household_matching_c_firm(households):
    """
    初始化消费品公司与居民部门的客户关系
    :param households:
    :return: [居民Agent，居民Agent]，字典，key为居民id，value为消费品公司id
    """
    c_firm_per_household = int(p.w.number_of_households / p.n.number_of_c_firms)
    households_id = [f"household_{i}" for i in range(int(p.w.number_of_households))]
    random.shuffle(households_id)
    household_matching_c_firm = {}
    for i, household_id in enumerate(households_id):
        h_i = i // c_firm_per_household
        c_firm_id = f"firm_c_{h_i}"
        household_matching_c_firm[household_id] = c_firm_id
    for household in households:
        household.consume_firm_id = household_matching_c_firm[household.household_id]
    return households, household_matching_c_firm


def ini_stockholder_of_firm(households: List[HouseHolds],
                            c_firms: List[Firms], k_firms: List[Firms],
                            banks: List[Banks],
                            num: int):
    """
    初始化
    :param households: 居民 Agent
    :param c_firms: 公司 Agent
    :param k_firms: 公司 Agent
    :param banks:  银行 Agent
    :param num: 平均下来每个公司多少个股东
    :return: [居民Agent，居民Agent]，字典，key为公司id，value 为居民id列表, 字典，key为银行id，value为居民id列表
    """
    stockholder_book_of_firm = {}
    stockholder_book_of_bank = {}
    households_id_map = {h.household_id: h for h in households}
    for firms in [c_firms, k_firms]:
        for f in firms:
            firm_id = f.firm_id
            stockholder_book_of_firm[firm_id] = []
            for i in range(num):
                household_id = random.choice(list(households_id_map.keys()))
                household = households_id_map[household_id]
                household.hold_stock_of_firm[firm_id] = 1 / num
                stockholder_book_of_firm[firm_id].append(household_id)
    for b in banks:
        bank_id = b.bank_id
        stockholder_book_of_bank[bank_id] = []
        for i in range(num):
            household_id = random.choice(list(households_id_map.keys()))
            household = households_id_map[household_id]
            household.hold_stock_of_bank[bank_id] = 1 / num
            stockholder_book_of_bank[bank_id].append(household_id)
    return households, stockholder_book_of_firm, stockholder_book_of_bank


def ini_c_firm_matching_k_firm(c_firms: List[Firms]):
    """
    初始化c公司与k公司匹配关系，k公司资本品卖给c公司
    :param c_firms: [公司类]
    :return: 字典，key为c公司id，value为k公司id
    """
    matching = {}
    firms_per_k_firm = int(p.n.number_of_c_firms / p.n.number_of_k_firms)
    c_firms_id = [f"firm_c_{i}" for i in range(p.n.number_of_c_firms)]
    random.shuffle(c_firms_id)
    for i, c_firm_id in enumerate(c_firms_id):
        k_i = i // firms_per_k_firm
        k_firm_id = f"firm_k_{k_i}"
        matching[c_firm_id] = k_firm_id
    for c_firm in c_firms:
        c_firm.supplier_k_firm_id = matching[c_firm.firm_id]
    return c_firms, matching


def ini_firm_match_bank_for_loan(c_firms: List[Firms], k_firms: List[Firms]):
    """
    初始化企业部门与银行的贷款关系
    :param c_firms: [公司类,公司类]
    :param k_firms:
    :return: 以字典的形式返回网络关系，key 为公司id ，value 为银行id
    """

    def ini_contract(firm: Firms, bank_id_: str):
        loan_contract = []
        firm.loans_bank_id = bank_id_
        for i, loan_amount in enumerate(firm.payment_of_loans_list):
            contract = {
                'amount': loan_amount, 'interest_rate': p.ir.interest_rate_of_loans, 'firm_id': firm.firm_id,
                'contract_year': 1992 - (20 - i), 'left_year': p.para.duration_or_loan - i, 'bank_id': bank_id_
            }
            loan_contract.append(LoanContract(contract))
        firm.batch_of_loan_contracts = loan_contract

    firms_matching_bank = {}
    banks_id = [f"bank_{i}" for i in range(p.n.number_of_banks)]
    firms = [*c_firms, *k_firms]
    np.random.shuffle(firms)
    firm_per_bank = len(firms) / len(banks_id)
    for i, firm in enumerate(firms):
        b_i = int(i // firm_per_bank)
        bank_id = random.choice(banks_id)
        firms_matching_bank[firm.firm_id] = banks_id[b_i]
        ini_contract(firm, bank_id)

    return c_firms, k_firms, firms_matching_bank


def transaction_flow_monitor(e: Events):
    """
    监测模拟过程中的资金流量表
    """
    print('-' * 40, f'START【year{e.credit_market.year}】资金流量表监控START', '-' * 40)
    print("政府收税", round(e.gov_collect_tax_amount, 2))
    print('-' * 40, f'END【year{e.credit_market.year}】资金流量表监控END', '-' * 40)


def balance_sheet_monitor(e: Events):
    """
    监测模拟过程中的资产负债表
    """
    print('-' * 40, f'START【year{e.credit_market.year}】资产负债表监控START', '-' * 40)
    print('政府财政存款（作为资产）', round(e.gov.deposits, 2), '中央银行财政存款（作为负债）', round(e.cb.treasury_deposits, 2))
    c_f_d = [c.deposits for c in e.credit_market.c_firms]
    k_f_d = [k.deposits for k in e.credit_market.k_firms]
    print('C公司存款', round(sum(c_f_d), 2), 'K公司存款', round(sum(k_f_d), 2))
    c_f_l = [c.loans for c in e.credit_market.c_firms]
    k_f_l = [k.loans for k in e.credit_market.k_firms]
    print('C公司贷款', round(sum(c_f_l), 2), 'K公司贷款', round(sum(k_f_l), 2))
    h_w = [h.deposits for h in e.credit_market.households]
    print('居民部门存款', sum(h_w))
    b_d = [b.deposits for b in e.credit_market.banks]
    b_l = [b.loans for b in e.credit_market.banks]
    print('【资产负债表存款等式】', '银行存款', round(sum(b_d), 2), 'H+C+K存款', round(sum(h_w) + sum(c_f_d) + sum(k_f_d), 2))
    print('【资产负债表贷款等式】', '银行贷款', round(sum(b_l), 2), 'C+K贷款', round(sum(c_f_l) + sum(k_f_l), 2))
    g_b = e.credit_market.government.bonds
    cb_b = e.credit_market.central_bank.bonds
    b_b = [b.bonds for b in e.credit_market.banks]
    print('中央银行持有债券', round(cb_b, 2), '银行持有债券', round(sum(b_b), 2))
    print('【债券等式】', '政府发行', round(g_b, 2), '中央银行和银行共同持有', round(cb_b + sum(b_b), 2))
    r_cb = e.credit_market.central_bank.reserves
    r_b = [b.reserves for b in e.credit_market.banks]
    print('【存款准备金等式】', '中央银行存款准备金', round(r_cb, 2), '银行存款准备金', round(sum(r_b), 2))
    print('-' * 40, 'END资产负债表END', '-' * 40)


if __name__ == "__main__":
    # 初始化居民部门
    all_households = ini_household_agents()
    # 初始化企业部门
    all_k_firms = ini_firms_agents(firm_type='Capital Goods')
    all_c_firms = ini_firms_agents(firm_type='Consumer Goods')
    # 初始化银行
    all_banks = ini_bank_agents()
    # 初始化政府
    gov = Government()
    # 初始化中央银行
    cb = CentralBank()
    # 初始化居民和公司的存款银行（居民、企业在存款市场与银行的关系）
    all_households, all_c_firms, all_k_firms, h_matching_deposit_bank, f_matching_deposit_bank = \
        ini_household_and_firm_matching_bank_for_deposit(households=all_households,
                                                         c_firms=all_c_firms,
                                                         k_firms=all_k_firms)
    # 初始化居民和C公司在消费品市场的供应关系
    all_households, household_match_c_firms = ini_household_matching_c_firm(households=all_households)
    # 初始化居民持有公司和银行的股票
    all_households, h_hold_firm_stocks, h_hold_bank_stocks = ini_stockholder_of_firm(
        households=all_households,
        c_firms=all_c_firms,
        k_firms=all_k_firms,
        banks=all_banks,
        num=p.a.average_stockholder_per_firm
    )
    # 初始化资本品的供应关系
    all_c_firms, c_firm_matching_k_firm = ini_c_firm_matching_k_firm(c_firms=all_c_firms)
    # 初始化贷款市场，企业和银行的供应关系
    all_c_firms, all_k_firms, firm_m_bank_for_loan = ini_firm_match_bank_for_loan(
        c_firms=all_c_firms, k_firms=all_k_firms)
    # 初始化信贷市场
    credit_market = CreditMarkets(year=INI_YEAR,
                                  c_firms=all_c_firms, k_firms=all_k_firms, banks=all_banks,
                                  households=all_households, government=gov, central_bank=cb,
                                  firm_match_bank_for_loan=firm_m_bank_for_loan,
                                  households_hold_firm_stocks=h_hold_firm_stocks,
                                  households_hold_bank_stocks=h_hold_bank_stocks,
                                  households_match_deposit_bank=h_matching_deposit_bank,
                                  firms_match_deposit_bank=f_matching_deposit_bank
                                  )
    # 初始化消费品市场
    consumption_goods_market = ConsumptionGoodsMarket(c_firms=all_c_firms, households=all_households,
                                                      households_matching_consumption_book=household_match_c_firms)
    # 初始化资本品市场
    capital_goods_market = CapitalGoodsMarket(year=INI_YEAR,
                                              c_firms=all_c_firms,
                                              k_firms=all_k_firms,
                                              c_firm_match_k_firm=c_firm_matching_k_firm
                                              )
    # 初始化劳动力市场
    labor_market = LaborMarket(
        gov=gov,
        c_firms=all_c_firms,
        k_firms=all_k_firms,
        households=all_households
    )
    # 遍历程序
    e = Events(government=gov,
               central_bank=cb,
               credit_markets=credit_market,
               consumption_markets=consumption_goods_market,
               capital_markets=capital_goods_market,
               labor_markets=labor_market,
               year=INI_YEAR,
               )
    # 　开始模拟
    balance_sheet_monitor(e)
    for i in range(3):
        e.run_a_episode()
        # balance_sheet_monitor(e)
        transaction_flow_monitor(e)
